package com.screencapture.core;

import java.awt.AWTException;
import java.awt.BasicStroke;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import javax.imageio.ImageIO;
import javax.swing.BoxLayout;
import javax.swing.ButtonGroup;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.SwingUtilities;
import javax.swing.border.EmptyBorder;

import com.screencapture.interfaces.ImageToClipboard;
import com.screencapture.slate.Slate;

public class ScreenCapture {

	private static Point start;
	private static Point end;
	private static JFrame mainWindow;
	private static JFrame screenWindow;
	private static JDialog settingsDialog;
	private static JPanel drawPanel;
	private static JPanel screenPanel;
	private static BufferedImage screen;
	private static Map<String, String> settings = new HashMap<String, String>();

	public static void main(String[] args) {
		new ScreenCapture().init();
	}

	private void init() {

		mainWindow = new JFrame("Screen Capture!!!");
		mainWindow.setResizable(false);
		mainWindow.setSize(100, 200);
		mainWindow.setLocationRelativeTo(null);
		mainWindow.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		
		JPanel contentPanel = new JPanel();
		contentPanel.setLayout(new BorderLayout(2, 2));
		contentPanel.setBorder(new EmptyBorder(5, 5, 5, 5));
		
		JButton capture = new JButton("Capture");
		capture.addActionListener(new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent arg0) {
				Runnable runnable = new Runnable() {

					@Override
					public void run() {
						mainWindow.setVisible(false);
						try {
							Thread.sleep(300);
						} catch (InterruptedException e) {
							e.printStackTrace();
						}
						initializeScreenWindow();

					}
				};
				SwingUtilities.invokeLater(runnable);
			}
		});

		contentPanel.add(capture, BorderLayout.WEST);

		JButton edit = new JButton("Edit");
		edit.addActionListener(new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent arg0) {
				Runnable runnable = new Runnable() {

					@Override
					public void run() {
						sendToEdit();
						mainWindow.setVisible(false);
					}
				};
				SwingUtilities.invokeLater(runnable);
			}
		});

		contentPanel.add(edit, BorderLayout.CENTER);

		JButton options = new JButton("Settings");
		options.addActionListener(new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent arg0) {
				Runnable runnable = new Runnable() {

					@Override
					public void run() {
						buildSettingsDialog();
					}
				};
				SwingUtilities.invokeLater(runnable);
			}
		});

		contentPanel.add(options, BorderLayout.EAST);

		mainWindow.add(contentPanel);
		mainWindow.pack();
		mainWindow.setVisible(true);

	}

	private void buildSettingsDialog() {
		if (settingsDialog == null) {
			settingsDialog = new JDialog();
			settingsDialog.setTitle("Settings");
			settingsDialog.setModal(true);

			JPanel contentPanel = new JPanel();
			contentPanel.setBorder(new EmptyBorder(3, 3, 3, 3));
			contentPanel.setLayout(new GridLayout(3, 2, 2, 2));

			contentPanel.add(new JLabel("Save Location"));

			ButtonGroup options = new ButtonGroup();

			JPanel optionsPanel = new JPanel();
			optionsPanel
					.setLayout(new BoxLayout(optionsPanel, BoxLayout.X_AXIS));

			final JRadioButton clipboard = new JRadioButton("Clipboard");
			final JRadioButton file = new JRadioButton("File");

			if (settings.containsKey("saveto")) {
				String option = settings.get("saveto");
				if (option.equals("clipboard")) {
					clipboard.setSelected(true);
				} else {
					file.setSelected(true);
				}
			} else {
				settings.put("saveto", "clipboard");
				clipboard.setSelected(true);
			}

			options.add(clipboard);
			optionsPanel.add(clipboard);
			options.add(file);
			optionsPanel.add(file);

			contentPanel.add(optionsPanel);

			JLabel outline = new JLabel("Outline");
			JCheckBox outlineCheck = new JCheckBox();

			contentPanel.add(outline);
			contentPanel.add(outlineCheck);

			JButton ok = new JButton("OK");
			ok.addActionListener(new ActionListener() {

				@Override
				public void actionPerformed(ActionEvent arg0) {
					String selection = clipboard.isSelected() ? "clipboard"
							: "file";
					settings.put("saveto", selection);
					settingsDialog.setVisible(false);
				}
			});

			contentPanel.add(ok);

			JButton cancel = new JButton("Cancel");
			cancel.addActionListener(new ActionListener() {

				@Override
				public void actionPerformed(ActionEvent arg0) {
					settingsDialog.setVisible(false);
				}
			});

			contentPanel.add(cancel);

			settingsDialog.getContentPane().add(contentPanel);
			settingsDialog.pack();
			settingsDialog.setLocationRelativeTo(mainWindow);
		}
		settingsDialog.setVisible(true);
	}

	protected void initializeScreenWindow() {
		Rectangle myRectangle = new Rectangle(getScreenDimension());
		screen = getScreenInRectangle(myRectangle);
		if (screen != null) {
			buildWindowWithScreen();
			setListeners();
			screenWindow.setVisible(true);
		} else {
			JDialog dialog = new JDialog();
			dialog.setTitle("ScreenCapture Error!!");
			dialog.setLocationRelativeTo(null);

			JLabel label = new JLabel(
					"There is a problem loading the application");
			label.setBorder(new EmptyBorder(10, 10, 10, 10));
			dialog.getContentPane().add(label);

			dialog.pack();
			dialog.setVisible(true);
		}
	}

	private void setListeners() {
		if (screenWindow.getMouseListeners().length == 0) {
			screenWindow.addMouseListener(new MouseAdapter() {
				@Override
				public void mousePressed(MouseEvent e) {
					start = e.getPoint();
				}

				@Override
				public void mouseReleased(MouseEvent e) {
					end = e.getPoint();

					if (start.distance(end) != 0) {
						captureToClipboard();
						// captureAndSaveToFile();
					}

					if (screenWindow != null) {
						start = end = null;
						screenWindow.setVisible(false);
						mainWindow.setVisible(true);
					}
				}
			});
		}

		if (screenWindow.getMouseMotionListeners().length == 0) {
			screenWindow.addMouseMotionListener(new MouseMotionAdapter() {
				@Override
				public void mouseDragged(MouseEvent e) {
					end = e.getPoint();
					drawPanel.repaint();
				}

			});
		}
	}

	@SuppressWarnings("unused")
	private void captureAndSaveToFile() {
		Rectangle rectangle = buildRectangle(start, end);
		try {
			BufferedImage image = getSubImage(screenPanel, rectangle);
			ImageIO.write(image, "png", new File(
					System.currentTimeMillis() + ".jpg"));
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	private void captureToClipboard() {
		Rectangle rectangle = buildRectangle(start, end);
		BufferedImage image = getSubImage(screenPanel, rectangle);
		final ImageToClipboard img = new ImageToClipboard(image);
		screen = image;
		Runnable runnable = new Runnable(){
			public void run() {
				Toolkit.getDefaultToolkit().getSystemClipboard().setContents(img, null);
			};
		};
		Thread t = new Thread(runnable);
		t.setDaemon(true);
		t.start();
	}

	private Rectangle buildRectangle(Point p1, Point p2) {
		if (p1.x < p2.x && p1.y < p2.y) {
			return new Rectangle(p1.x, p1.y, p2.x - p1.x, p2.y - p1.y);
		} else if (p1.x < p2.x && p1.y > p2.y) {
			return new Rectangle(p1.x, p2.y, p2.x - p1.x, p1.y - p2.y);
		} else if (p1.x > p2.x && p1.y > p2.y) {
			return new Rectangle(p2.x, p2.y, p1.x - p2.x, p1.y - p2.y);
		} else {
			return new Rectangle(p2.x, p1.y, p1.x - p2.x, p2.y - p1.y);
		}
	}

	private void buildWindowWithScreen() {
		if (screenWindow == null) {
			screenWindow = new JFrame();
			screenWindow.setBounds(new Rectangle(getScreenDimension()));
			// screenWindow.setAlwaysOnTop(true);
			screenWindow.setUndecorated(true);
			screenPanel = new JPanel() {

				private static final long serialVersionUID = 4179177663208901709L;

				@Override
				public void paintComponent(Graphics g) {
					super.paintComponent(g);
					g.drawImage(screen, 0, 0, null);
				}

			};
			screenPanel.setSize(getScreenDimension());
			screenWindow.getLayeredPane().add(screenPanel, 0);

			drawPanel = new JPanel() {
				private static final long serialVersionUID = 87102084201915159L;

				@Override
				public void paintComponent(Graphics g) {
					super.paintComponent(g);

					if (start != null && end != null) {
						g.setXORMode(new Color(0x66FFFFFF, true));
						Rectangle newRect = buildRectangle(start, end);
						Graphics2D g2d = (Graphics2D) g;
						g2d.setStroke(new BasicStroke(2f));
						g2d.fillRect(newRect.x, newRect.y, newRect.width,
								newRect.height);
					}
				}

			};
			drawPanel.setSize(getScreenDimension());
			drawPanel.setOpaque(false);
			screenWindow.getLayeredPane().add(drawPanel, 0);

		}
	}

	private BufferedImage getScreenInRectangle(Rectangle myRectangle) {
		try {
			Robot robot = new Robot();
			BufferedImage retImg = robot.createScreenCapture(myRectangle);
			return retImg;
		} catch (AWTException e) {
			e.printStackTrace();
			return null;
		}
	}

	private BufferedImage getSubImage(JPanel panel, Rectangle rectangle) {

		BufferedImage img = screen.getSubimage(rectangle.x, rectangle.y,
				rectangle.width, rectangle.height);
		return img;
	}

	private Dimension getScreenDimension() {
		return Toolkit.getDefaultToolkit().getScreenSize();
	}

	public static void showMe() {
		mainWindow.setVisible(true);
	}

	public void sendToEdit() {
		Slate slate = new Slate(screen);
		slate.init();
	}
}
